#include "../console-common.h"
#include <stdarg.h>
#include <cstdlib>

#ifdef _MSC_VER
unsigned msvc_ctz(unsigned a)
{
	unsigned long i;
	_BitScanForward(&i, a);
	return i;
}

unsigned msvc_clz(unsigned a)
{
	unsigned long i;
	_BitScanReverse(&i, a);
	return 31 - i;
}
#endif

void swap_int(int & a , int & b) { int t = a; a = b; b = t; }

#define SET_CFUNCTION(L, NAME, func)\
	(lua_pushcfunction(L, func),\
	lua_setfield(L, -2, NAME))

lua_State * luacon_regnewstate()
{
	lua_State * L = (lua_State*)NULL;
	for (int i = 0; i < REG_MAX_LUA_STATES; i++)
	{
		if (luacon_stateRegTable[2*i] == (intptr_t)NULL)
		{
			L = luaL_newstate();
			luacon_stateRegTable[2*i] = (intptr_t)L;
			luacon_stateRegTable[2*i+1] = (intptr_t)NULL;
			break;
		}
	}
	return L;
}

void luacon_reg_clearupmem (lua_State * L)
{
	if (L == NULL)
		return;
	for (int i = 0; i < REG_MAX_LUA_STATES; i++)
	{
		if (luacon_stateRegTable[2*i] == (intptr_t)L)
		{
			free((void*)(luacon_stateRegTable[2*i+1]));
			luacon_stateRegTable[2*i+1] = (intptr_t)NULL;
			break;
		}
	}
}

void luaL_register_ext (lua_State *L, const luaL_Reg *l)
{
	bool first = true;
	for (int i = 0; l[i].name != NULL; i++)
	{
		if (first)
			first = false, lua_newtable(L);
		if (l[i].func)
			SET_CFUNCTION(L, l[i].name, l[i].func);
		else
			first = true, lua_setfield(L, -2, l[i].name);
	}
}

void luaL_set_aliases (lua_State *L, const char** str_list)
{
	while (*str_list != NULL)
		lua_getfield(L, -1, str_list[0]),
		lua_setfield(L, -2, str_list[1]),
		str_list += 2;
}

void luaL_va_optints (lua_State *L, int start, int value, ...)
{
	va_list vl;
	va_start(vl, value);
	int* iptr;
	while (iptr = va_arg(vl, int*))
		*iptr = luaL_optint(L, start++, value);
}

void luaL_va_optints (lua_State *L, int start, int** args, int* value)
{
	while (args)
		**args = luaL_optint(L, start++, *value),
		args++, value++;
}

int luaL_va_setfield_ints (lua_State *L, const void* _t)
{
	struct st0 {const char* name; int value;} *t;
	int i;
	t = (st0*)_t;
	
	for (i = 0; t[i].name != NULL; i++)
		lua_pushinteger(L, t[i].value),
		lua_setfield(L, -2, t[i].name);
	return i + 1;
}

void luaL_va_tointegers (lua_State *L, int start, ...)
{
	va_list vl;
	va_start(vl, start);
	int* iptr;
	while (iptr = va_arg(vl, int*))
		*iptr = lua_tointeger(L, start++);
}

#if LUA_VERSION_NUM < 502
extern "C"
{
void luaL_set_cfuncs (lua_State *L, const luaL_Reg *l)
{
	for (; l->name; l++) SET_CFUNCTION(L, l->name, l->func);
}
}
#endif

#define _SWAP_T0(i) i, i + 0x80, i + 0x40, i + 0xC0, i + 0x20, i + 0xA0, i + 0x60, i + 0xE0,
#define _SWAP_T1(i) _SWAP_T0(i) _SWAP_T0(i + 0x10) _SWAP_T0(i + 0x08) _SWAP_T0(i + 0x18)
#define _SWAP_T2(i) _SWAP_T1(i) _SWAP_T1(i + 0x04) _SWAP_T1(i + 0x02) _SWAP_T1(i + 0x06)

static unsigned char __reverse_bit_table[256] = { _SWAP_T2(0) _SWAP_T2(1) };

unsigned char bit_reverse (unsigned char x) { return __reverse_bit_table[x]; }
